package com.jimmyhsu.ecnudaowei.coursetable.checkin;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.jimmyhsu.ecnudaowei.MyApplication;
import com.jimmyhsu.ecnudaowei.R;
import com.jimmyhsu.ecnudaowei.common.Config;
import com.jimmyhsu.ecnudaowei.coursetable.face.Face;
import com.jimmyhsu.ecnudaowei.coursetable.face.FaceUtils;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;

public class CameraCheckInActivity extends AppCompatActivity {

//    @BindView(R.id.id_cci_shot)
//    FloatingActionButton mFabShot;

    private static final String EXTRA_COURSE = "extra_course";
    private static final String BUNDLE_RESULT = "bundle_result";
    private static final int MSG_DETECT_SUCCESS = 0;
    private static final int MSG_UPLOAD_RECOGNIZED_FAIL = 1;
    private static final int MSG_UPLOAD_RECOGNIZED_OK = 2;
    private static final int MSG_BD_RECOGNIZED_OK = 3;
    private static final int SOURCE_BD = 1;
    private static final int SOURCE_FACEPP = 0;



    @BindView(R.id.id_cci_toolbar)
    Toolbar mToolbar;

    private String mCourseId;
    private Handler mHandler;
    private ExecutorService mThreadPool;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_check_in);
        ButterKnife.bind(this);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });
        setTitle("");
        mCourseId = getIntent().getStringExtra(EXTRA_COURSE);
        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case MSG_DETECT_SUCCESS:
                    String result = msg.getData().getString(BUNDLE_RESULT);
                    List<Face> facesList = new ArrayList<>();
                    try {
                        JSONObject resultObj = new JSONObject(result);
                        JSONArray faces = resultObj.getJSONArray("faces");
                        for (int i = 0; i < faces.length(); i++) {
                            JSONObject face = faces.getJSONObject(i);
                            JSONObject faceRect = face.getJSONObject("face_rectangle");
                            Face faceBean = new Face(faceRect.getInt("width"), faceRect.getInt("top"),
                                    faceRect.getInt("left"), faceRect.getInt("height"), face.getString("face_token"));
                            facesList.add(faceBean);
                        }
                        searchFaces(facesList);
                        EventBus.getDefault().post(facesList);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                    case MSG_UPLOAD_RECOGNIZED_FAIL:
                        String reason = (String) msg.obj;
                        Toast.makeText(CameraCheckInActivity.this, "签到失败: " + reason, Toast.LENGTH_SHORT).show();
                        break;
                    case MSG_UPLOAD_RECOGNIZED_OK:
                        Toast.makeText(CameraCheckInActivity.this, "签到成功", Toast.LENGTH_SHORT).show();
                        finish();
                        break;
                    case MSG_BD_RECOGNIZED_OK:
                        String facesRaw = (String) msg.obj;
                        final List<String> faces = new ArrayList<>(Arrays.asList(facesRaw.split(";")));
                        mThreadPool.submit(new Runnable() {
                            @Override
                            public void run() {
                                uploadRecognizedFaces(faces, SOURCE_BD);
                            }
                        });
                        break;
                }

            }
        };
        mThreadPool = Executors.newCachedThreadPool();
    }

    private void searchFaces(final List<Face> facesList) {
        mThreadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                List<String> matchedTokens = new ArrayList<>();
                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl(Config.FACEPP_URL)
                        .addConverterFactory(ScalarsConverterFactory.create())
                        .build();
                SearchFaceService service = retrofit.create(SearchFaceService.class);
                for (Face face : facesList) {
                    for (int i = 0; i < 5; i++) {
                        Log.e("haha", Config.API_KEY + ", " + Config.API_SECRET + ", " + face.getFace_token() + ", " + mCourseId);
                        Call<String> call = service.searchFace(Config.API_KEY, Config.API_SECRET,
                                face.getFace_token(), mCourseId);
                        Response<String> response = null;
                        try {
                            response = call.execute();
                            JSONObject responseObj = new JSONObject(response.body());
                            JSONArray faces = responseObj.getJSONArray("results");
                            String matchedToken = faces.getJSONObject(0).getString("face_token");
                            matchedTokens.add(matchedToken);
                            EventBus.getDefault().post(face);
                            break;
                        } catch (Exception e) {
                            if (response != null && response.body() != null) {
                                Log.e("haha", response.body());
                            } else {
                                Log.e("haha", "facepp no response");
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }
                        }
                    }
                }
                uploadRecognizedFaces(matchedTokens, 0);
            }
        });

    }

    private void uploadRecognizedFaces(List<String> matchedTokens, int source) {
        StringBuilder sb = new StringBuilder();
        for (String tokens : matchedTokens) {
            sb.append(tokens).append(';');
            Log.e("haha", "match complete: " + tokens);
        }
        if (sb.length() > 0) {
            sb.substring(0, sb.length() - 1);
        }
        UploadFaceRecognized uploadService = new Retrofit.Builder()
                .baseUrl(Config.SERVER_URL)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build()
                .create(UploadFaceRecognized.class);
        MyApplication app = MyApplication.getInstance(CameraCheckInActivity.this);
        Log.e("haha", app.getName() + ", " + app.getPassword() + ", " + mCourseId + ", " + sb.toString() + ", " + String.valueOf(source));
        Call<String> call = uploadService.uploadRecognizedTokens(app.getName(),
                app.getPassword(),
                mCourseId,
                sb.toString(),
                String.valueOf(source));
        try {
            Response<String> response = call.execute();
            String reason;
            Message msg = Message.obtain();
            msg.what = MSG_UPLOAD_RECOGNIZED_FAIL;
            Log.e("haha", "php response: " + response.code() + ", " + response.body());
            if (response.body() == null) {
                reason = "服务器异常";
            } else if (response.body().equals("permission")) {
                reason = "您没有权限";
            } else if (response.body().equals("success")) {
                reason = "success";
                msg.what = MSG_UPLOAD_RECOGNIZED_OK;
            } else {
                reason = "未知异常";
            }
            msg.obj = reason;
            mHandler.sendMessage(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onPictureCaptured(Bitmap bitmap) {
        final File file = new File(Environment.getExternalStorageDirectory() + "/tempp.jpg");
        try {
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        mThreadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    boolean success = false;
                    String path = Environment.getExternalStorageDirectory() + "/tempp.jpg";
                    for (int i = 0; i < 3; i++) {
                        String result = FaceUtils.detect(path);
                        if (result != null && !result.contains("error_message")) {
                            success = true;
                            Message msg = Message.obtain();
                            msg.what = MSG_DETECT_SUCCESS;
                            Bundle bundle = new Bundle();
                            bundle.putString(BUNDLE_RESULT, result);
                            msg.setData(bundle);
                            mHandler.sendMessage(msg);
                            break;
                        } else {
                            Thread.sleep(1000);
                        }
                    }
                    if (!success) {
                        HashMap<String, Object> options = new HashMap<>();
                        ArrayList<String> paths = new ArrayList<>();
                        paths.add(path);
                        options.put("user_top_num", "20");
                        JSONObject bdObj = FaceUtils.getBaiduInstance().identifyUser(mCourseId.replace('.', '_'),
                                paths, options);
                        Log.e("haha", "bd res: " + bdObj.toString());
                        JSONArray faces = bdObj.getJSONArray("results");
                        int length = faces.length();
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < length; i++) {
                            String uid = faces.getJSONObject(i).getString("uid");
                            sb.append(uid).append(';');
                        }
                        if (sb.length() > 0) {
                            sb.substring(0, sb.length() - 1);
                        }
                        Message msg = Message.obtain();
                        msg.obj = sb.toString();
                        msg.what = MSG_BD_RECOGNIZED_OK;
                        mHandler.sendMessage(msg);
                        Toast.makeText(CameraCheckInActivity.this, "Face++异常，使用百度api代替", Toast.LENGTH_SHORT).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Toast.makeText(CameraCheckInActivity.this, "接口异常,请稍后再试", Toast.LENGTH_SHORT).show();
                } finally {
                    file.delete();
                }
            }
        });
    }

    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
        mThreadPool.shutdownNow();
    }

    public static void startActivity(Context context, String courseId) {
        Intent intent = new Intent(context, CameraCheckInActivity.class);
        intent.putExtra(EXTRA_COURSE, courseId);
        context.startActivity(intent);
    }

    interface SearchFaceService {
        @FormUrlEncoded
        @POST("facepp/v3/search")
        Call<String> searchFace(@Field("api_key") String apiKey,
                                @Field("api_secret") String apiSecret,
                                @Field("face_token") String faceToken,
                                @Field("outer_id") String outerId);
    }

    interface UploadFaceRecognized {
        @FormUrlEncoded
        @POST("phpprojects/face/cameraCheckInSuccess.php")
        Call<String> uploadRecognizedTokens(@Field("username") String username,
                                            @Field("password") String password,
                                            @Field("course_id") String courseId,
                                            @Field("tokens") String tokens,
                                            @Field("source") String source);
    }
}
